package com.zgjkhis.modules.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageInfo;
import com.zgjkhis.common.service.impl.BaseServiceImpl;
import com.zgjkhis.domain.PageResult;
import com.zgjkhis.exception.ServiceException;
import com.zgjkhis.modules.enums.DrugTypeEnum;
import com.zgjkhis.modules.security.security.LoginUserUtil;
import com.zgjkhis.modules.system.domain.Drug;
import com.zgjkhis.modules.system.domain.DrugInventory;
import com.zgjkhis.modules.system.domain.DrugInventoryDetail;
import com.zgjkhis.modules.system.domain.DrugWareHousingDetail;
import com.zgjkhis.modules.system.domain.vo.DrugInventoryDetailVO;
import com.zgjkhis.modules.system.domain.vo.DrugInventoryVo;
import com.zgjkhis.modules.system.req.InventoryDetailReq;
import com.zgjkhis.modules.system.req.InventoryExamineReq;
import com.zgjkhis.modules.system.service.DrugInventoryDetailService;
import com.zgjkhis.modules.system.service.DrugInventoryService;
import com.zgjkhis.modules.system.service.DrugService;
import com.zgjkhis.modules.system.service.DrugWareHousingDetailService;
import com.zgjkhis.modules.system.service.dto.DrugInventoryQueryCriteria;
import com.zgjkhis.modules.system.service.dto.DrugWareHousingDetailDto;
import com.zgjkhis.modules.system.service.mapper.DrugInventoryMapper;
import com.zgjkhis.modules.util.CharUtil;
import com.zgjkhis.utils.DateUtils;
import com.zgjkhis.utils.FileUtil;
import com.zgjkhis.utils.RandomUtils;
import com.zgjkhis.utils.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;

// 默认不使用缓存
//import org.springframework.cache.annotation.CacheConfig;
//import org.springframework.cache.annotation.CacheEvict;
//import org.springframework.cache.annotation.Cacheable;

/**
 * @Author yzq
 * @Description 盘点单
 * @Date 2021/6/23 9:47
 * @Param
 * @return
 **/
@Slf4j
@Service
@AllArgsConstructor
//@CacheConfig(cacheNames = "user")
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class DrugInventoryServiceImpl extends BaseServiceImpl<DrugInventoryMapper, DrugInventory> implements DrugInventoryService {

    private final DrugWareHousingDetailService drugWareHousingDetailService;
    private final DrugInventoryDetailService drugInventoryDetailService;
    private final DrugService drugService;

    @Override
    public void dowonload(List<DrugWareHousingDetailDto> drugWareHousingDetailDtoList, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        Integer drugType = 1;
        for (DrugWareHousingDetailDto drugWareHousingDetailDto : drugWareHousingDetailDtoList) {
            drugType = drugWareHousingDetailDto.getDrugType();
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("批次id", drugWareHousingDetailDto.getId());
            map.put("药品id", drugWareHousingDetailDto.getDrugId());
            map.put("药品名称", drugWareHousingDetailDto.getDrugName());
            map.put("药品状态", (drugWareHousingDetailDto.getDrugStatus() == 0 ? "正常" : "失效"));
            map.put("规格", drugWareHousingDetailDto.getDrugSpec());
            map.put("厂家", drugWareHousingDetailDto.getDrugManufactor());
            map.put("入库批号", drugWareHousingDetailDto.getWareHousingNo());
            map.put("批号", drugWareHousingDetailDto.getBatchNo());
            map.put("有效期", drugWareHousingDetailDto.getTermOfValidity());
            map.put("药品类型", DrugTypeEnum.findByCode(drugWareHousingDetailDto.getDrugType()));
            map.put("库存单位", drugWareHousingDetailDto.getPackageUnit());
            map.put("系统数量", drugWareHousingDetailDto.getLeftCount());

            if (drugWareHousingDetailDto.getDrugType() == 1) {
                //饮片量 kg
                if ("g".equals(drugWareHousingDetailDto.getDoseUnit())) {
                    Double leftCount = drugWareHousingDetailDto.getLeftCount() / 1000.000;
                    map.put("实际数量", leftCount.toString());
                } else {
                    map.put("实际数量", drugWareHousingDetailDto.getLeftCount());
                }
            } else {
                map.put("实际数量", drugWareHousingDetailDto.getLeftCount());
            }
            //颗粒剂存在瓶当量
            if (drugWareHousingDetailDto.getDrugType() == 2 && !CharUtil.isEmpty(drugWareHousingDetailDto.getCoefficient())) {
                if ("g".equals(drugWareHousingDetailDto.getCoefficientName())) {
                    map.put("瓶当量系数(相当于饮片)", 0);
                    map.put("克当量", drugWareHousingDetailDto.getEquivalent());
                    //进一
                    int klsl = (int) Math.floor(Double.valueOf(drugWareHousingDetailDto.getLeftCount()) / drugWareHousingDetailDto.getEquivalent());
                    map.put("瓶装规格", drugWareHousingDetailDto.getCoefficient() / drugWareHousingDetailDto.getEquivalent());
                    map.put("颗粒剂数量", klsl);
                    double floor = 0;
                    map.put("瓶数", floor);
                    map.put("实际瓶数", floor);
                    map.put("颗粒剂散装量", ((drugWareHousingDetailDto.getLeftCount() - floor * drugWareHousingDetailDto.getCoefficient()) / drugWareHousingDetailDto.getEquivalent()));
                } else {
                    map.put("瓶当量系数(相当于饮片)", drugWareHousingDetailDto.getCoefficient());
                    map.put("克当量", drugWareHousingDetailDto.getEquivalent());
                    //进一
                    int klsl = (int) Math.floor(Double.valueOf(drugWareHousingDetailDto.getLeftCount()) / drugWareHousingDetailDto.getEquivalent());
                    map.put("瓶装规格", drugWareHousingDetailDto.getCoefficient() / drugWareHousingDetailDto.getEquivalent());
                    map.put("颗粒剂数量", klsl);
                    double floor = Math.floor(drugWareHousingDetailDto.getLeftCount() / drugWareHousingDetailDto.getCoefficient());
                    map.put("瓶数", floor);
                    map.put("实际瓶数", floor);
                    map.put("颗粒剂散装量", ((drugWareHousingDetailDto.getLeftCount() - floor * drugWareHousingDetailDto.getCoefficient()) / drugWareHousingDetailDto.getEquivalent()));
                }
            } else {
                map.put("瓶当量系数", "");
                map.put("克当量", "");
                map.put("瓶装规格", "");
                map.put("颗粒剂数量", "");
                map.put("瓶数", "");
                map.put("实际瓶数", "");
                map.put("散装量", "");
            }
            list.add(map);
        }
        FileUtil.downloadExcelForPan(list, response, drugType);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchInventory(MultipartFile file) throws IOException {
        ExcelReader excelReader = ExcelUtil.getReader(file.getInputStream());
        List<List<Object>> listAll = excelReader.read();
        DrugInventory drugInventory = new DrugInventory();
        String inventoryNo = DateUtils.dateTimeNow() + RandomUtils.getRandomNumbers(6);
        drugInventory.setInventoryNo(inventoryNo);
        drugInventory.setCreateUserId(SecurityUtils.getUserId().toString());
        drugInventory.setCreateUserName(LoginUserUtil.getNickName());
        drugInventory.setPharmacyId(LoginUserUtil.getPharmId());
        drugInventory.setStatus(DrugInventory.STATUS_WAIT);
        Integer inventoryType = 0;
        // 盈亏数量
        Integer num = 0;
        // 盈亏成本金额
        BigDecimal principal = BigDecimal.ZERO;
        // 盈亏零售金额
        BigDecimal sales = BigDecimal.ZERO;
        List<DrugInventoryDetail> detailsList = new ArrayList<>();
        int len = listAll.size();
        for (int i = 1; i < len; i++) {
            List<Object> rowlist = listAll.get(i);
            try {
                Long id = (Long) rowlist.get(0);
                DrugWareHousingDetail wareHousingDetail = drugWareHousingDetailService.getById(id);

                if (!CharUtil.isEmpty(wareHousingDetail)) {
                    Drug drug = drugService.getById(wareHousingDetail.getDrugId());
                    inventoryType = drug.getDrugType();
                    // 存在入库数据
                    // 实际数量
                    Integer realLeft;
                    if (drug.getDrugType() == 1 && "g".equals(drug.getDoseUnit())) {
                        Double value = Double.valueOf(rowlist.get(12).toString());
                        realLeft = (int) (value * 1000);
                    } else {
                        realLeft = Integer.valueOf(rowlist.get(12).toString());
                    }
                    // 实际减去入库 = 盈亏数量
                    Integer tempNum = realLeft - wareHousingDetail.getLeftCount();
                    if (drug.getDrugType() == 2) {
                        if (CharUtil.isEmpty(wareHousingDetail.getCoefficient())) {
                            throw new ServiceException("颗粒剂【" + drug.getDrugName() + "】当量为空,盘点失败,请补充当量后，在盘点");
                        }
                        //实际数量*系数
                        realLeft = (int) (Double.valueOf(rowlist.get(18).toString()) * wareHousingDetail.getCoefficient());
                        //颗粒剂散装量
                        Double minTemp = Double.valueOf(rowlist.get(19).toString());
                        //饮片散装量
                        Integer min = (int) (minTemp * wareHousingDetail.getEquivalent());
                        //实际减去入库 =盈亏数量
                        tempNum = realLeft + min - wareHousingDetail.getLeftCount();
                        //                    if(tempNum<drug.getCoefficient()){
                        //                        tempNum=0;
                        //                    }
                        realLeft = realLeft + min;
                    }
                    if (tempNum != 0) {
                        // 实际数量与剩余数量不对等
                        BigDecimal temPrincipal;
                        // 颗粒剂成本价
                        if (drug.getDrugType().equals(DrugTypeEnum.PFKL.getCode())) {
                            // 盈亏成本金额
                            temPrincipal = wareHousingDetail.getSelfPrice().multiply(BigDecimal.valueOf(tempNum));
                        } else {
                            // 盈亏成本金额
                            temPrincipal = wareHousingDetail.getCostPrice().multiply(BigDecimal.valueOf(tempNum));
                        }
                        //盈亏零售金额
                        BigDecimal tempSales = wareHousingDetail.getSalePrice().multiply(BigDecimal.valueOf(tempNum));
                        DrugInventoryDetail temp = new DrugInventoryDetail();
                        temp.setInventoryNo(inventoryNo);
                        temp.setDrugId(wareHousingDetail.getDrugId());
                        temp.setDrugName(wareHousingDetail.getDrugName());
                        temp.setWarehousingDetailId(wareHousingDetail.getId());
                        temp.setDrugManufactor(wareHousingDetail.getDrugManufactor());
                        temp.setStock(wareHousingDetail.getLeftCount());
                        temp.setStockReal(realLeft);
                        temp.setPharmacyId(LoginUserUtil.getPharmId());
                        temp.setProfitLossNum(tempNum);
                        temp.setProfitLossPrincipal(temPrincipal);
                        temp.setProfitLossSales(tempSales);
                        num = num + tempNum;
                        principal = principal.add(temPrincipal);
                        sales = sales.add(tempSales);
                        detailsList.add(temp);
                    }
                } else {
                    log.error("盘点导入药品出错id：{}", id);
                }

            } catch (ClassCastException ex) {
                int rows = i + 1;
                throw new ServiceException("第" + rows + "行数据错误，请核对格式，如：是否多标点符号等，建议核对以医药品编码、批次、实际重量为主");
            } catch (Exception e) {
                log.error("数据错误：{}", e);
                int rows = i + 1;
                throw new ServiceException("第" + rows + "行数据错误，请核对");
            }
        }
        drugInventory.setInventoryType(inventoryType);
        drugInventory.setProfitLossNum(num);
        drugInventory.setProfitLossSales(sales);
        drugInventory.setProfitLossPrincipal(principal);
        drugInventoryDetailService.saveBatch(detailsList);
        this.save(drugInventory);
    }

    @Override
    public PageResult<DrugInventory> findAllByPageable(DrugInventoryQueryCriteria criteria, Pageable pageable) {
        getPage(pageable);
        PageInfo<DrugInventory> page = new PageInfo<>(baseMapper.findAllByPageable(criteria));
        return PageResult.data(page);
    }

    @Override
    public void dowonloadInventoryDetail(List<DrugInventoryDetail> details, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (int i = 0; i < details.size(); i++) {
            DrugInventoryDetail drugInventoryDetail = details.get(i);
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("序号", (i + 1));
            map.put("药品名称", drugInventoryDetail.getDrugName());
            map.put("生产厂商", drugInventoryDetail.getDrugManufactor());
            map.put("库存", drugInventoryDetail.getStock());
            map.put("盘点实际库存", drugInventoryDetail.getStockReal());
            map.put("盈亏数量", drugInventoryDetail.getProfitLossNum());
            map.put("盈亏成本金额(元)", drugInventoryDetail.getProfitLossPrincipal());
            map.put("盈亏零售金额(元)", drugInventoryDetail.getProfitLossSales());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }

    @Override
    public void examine(InventoryExamineReq request) {
        DrugInventory drugInventory = super.getById(request.getId());
        if (drugInventory == null) {
            throw new ServiceException(String.format("无效的盘点记录【%s】", request.getId()));
        }
        if (drugInventory.getStatus() != DrugInventory.STATUS_WAIT) {
            throw new ServiceException("操作失败，记录已审核！");
        }

        // 审核中、已审核 允许编辑盘点实际库存
        if (request.getStatus() == DrugInventory.STATUS_ADOPT
                || request.getStatus() == DrugInventory.STATUS_WAIT) {
            if (request.getDetails() != null && !request.getDetails().isEmpty()) {
                // 盈亏数量
                Integer num = 0;
                // 盈亏成本金额
                BigDecimal principal = BigDecimal.ZERO;
                // 盈亏零售金额
                BigDecimal sales = BigDecimal.ZERO;
                List<DrugInventoryDetail> detailsList = new ArrayList<>();

                DrugWareHousingDetail wareHousingDetail;
                DrugInventoryDetail inventoryDetail;
                DrugInventoryDetail temp;
                BigDecimal temPrincipal;

                for (InventoryDetailReq item : request.getDetails()) {
                    inventoryDetail = this.drugInventoryDetailService.getById(item.getId());
                    if (inventoryDetail == null) {
                        if (request.getDetails() == null || request.getDetails().isEmpty()) {
                            throw new ServiceException(String.format("操作失败，无效的盘点记录：", item.getId()));
                        }
                    }
                    wareHousingDetail = drugWareHousingDetailService.getById(inventoryDetail.getWarehousingDetailId());
                    if (!CharUtil.isEmpty(wareHousingDetail)) {
                        Drug drug = drugService.getById(wareHousingDetail.getDrugId());
                        // 实际数量
                        Integer realLeft;
                        if (drug.getDrugType() == 1 && "g".equals(drug.getDoseUnit())) {
                            realLeft = (int) (item.getStockReal() * 1000);
                        } else {
                            realLeft = item.getStockReal().intValue();
                        }
                        // 实际减去入库 = 盈亏数量
                        Integer tempNum = realLeft - wareHousingDetail.getLeftCount();
                        //                    if(drug.getDrugType() == 2){
                        //                        if(CharUtil.isEmpty(drug.getCoefficient())){
                        //                            throw new ServiceException("颗粒剂【"+drug.getDrugName()+"】当量为空,盘点失败,请补充当量后，在盘点");
                        //                        }
                        //                        // 实际数量*系数
                        //                        realLeft = wareHousingDetail.getLeftCount();
                        //                        // 颗粒剂散装量
                        //                        Double san = (wareHousingDetail.getLeftCount()-((wareHousingDetail.getLeftCount() / wareHousingDetail.getCoefficient())*wareHousingDetail.getCoefficient())) / wareHousingDetail.getEquivalent();
                        //                        Integer min = san.intValue();
                        //                        //饮片散装量
                        //                        min=(int)(min*wareHousingDetail.getEquivalent());
                        //                        //实际减去入库 =盈亏数量
                        //                        tempNum=realLeft+min-wareHousingDetail.getLeftCount();
                        ////                    if(tempNum<drug.getCoefficient()){
                        ////                        tempNum=0;
                        ////                    }
                        //                        realLeft=realLeft+min;
                        //                    }
                        //                    if(tempNum != 0){
                        // 实际数量与剩余数量不对等
                        // 颗粒剂成本价
                        if (drug.getDrugType().equals(DrugTypeEnum.PFKL.getCode())) {
                            // 盈亏成本金额
                            temPrincipal = wareHousingDetail.getSelfPrice().multiply(BigDecimal.valueOf(tempNum));
                        } else {
                            // 盈亏成本金额
                            temPrincipal = wareHousingDetail.getCostPrice().multiply(BigDecimal.valueOf(tempNum));
                        }
                        //盈亏零售金额
                        BigDecimal tempSales = wareHousingDetail.getSalePrice().multiply(BigDecimal.valueOf(tempNum));
                        temp = new DrugInventoryDetail();
                        temp.setId(item.getId());
                        temp.setStockReal(realLeft);
                        temp.setProfitLossNum(tempNum);
                        temp.setProfitLossPrincipal(temPrincipal);
                        temp.setProfitLossSales(tempSales);
                        num = num + tempNum;
                        principal = principal.add(temPrincipal);
                        sales = sales.add(tempSales);
                        detailsList.add(temp);
                        if (request.getStatus() == DrugInventory.STATUS_ADOPT) {
                            // 修改原入库库存数量
                            DrugWareHousingDetail tempWare = new DrugWareHousingDetail();
                            tempWare.setId(wareHousingDetail.getId());
                            tempWare.setLeftCount(realLeft);
                            drugWareHousingDetailService.updateById(tempWare);
                            // 修改入库药品总库存
                            Drug temDrug = new Drug();
                            temDrug.setId(wareHousingDetail.getDrugId());
                            temDrug.setStock(drug.getStock() + tempNum);
                            drugService.updateById(temDrug);
                        }
                        //                    }
                    } else {
                        throw new ServiceException(String.format("操作失败，未找到批次信息：", inventoryDetail.getWarehousingDetailId()));
                    }
                }
                drugInventory.setProfitLossNum(num);
                drugInventory.setProfitLossSales(sales);
                drugInventory.setProfitLossPrincipal(principal);
                drugInventoryDetailService.updateBatchById(detailsList);
            }

        }

        // 审核通过、取消操作，更新审核状态
        if (request.getStatus() == DrugInventory.STATUS_ADOPT
                || request.getStatus() == DrugInventory.STATUS_CANCEL) {
            drugInventory.setStatus(request.getStatus());
            drugInventory.setExamineTime(new Date());
            drugInventory.setExamineUserName(LoginUserUtil.getNickName());
            drugInventory.setExamineUserId(SecurityUtils.getUserId().toString());
        }
        super.updateById(drugInventory);
    }

    @Override
    public DrugInventoryVo getDetail(String id) {
        DrugInventory drugInventory = super.getById(id);
        DrugInventoryVo drugInventoryVo = new DrugInventoryVo();
        BeanUtil.copyProperties(drugInventory, drugInventoryVo);
        List<DrugInventoryDetail> list = drugInventoryDetailService.list(Wrappers.<DrugInventoryDetail>query().lambda().eq(DrugInventoryDetail::getInventoryNo, drugInventory.getInventoryNo()));
        List<DrugInventoryDetailVO> detailVOList = new ArrayList<>();
        Drug drug;
        for (DrugInventoryDetail inventoryDetail : list) {
            drug = this.drugService.getById(inventoryDetail.getDrugId());
            if (drug != null) {
                detailVOList.add(new DrugInventoryDetailVO(inventoryDetail, drug.getDrugType(), drug.getDoseUnit()));
            }
        }
        drugInventoryVo.setList(detailVOList);
        return drugInventoryVo;
    }


}
